// Number of Joker card
var Card_Joker = 16;
exports.Card_Joker = Card_Joker;

/*
 *
 *       @enum
 *   Dealabel type card
 *
 * */
var DealType = {
    None: 0, // None for dealing
    Pair: 1, // Dealing tour is pair (33, 444, 5555, 66666)
    Sequ: 2  // 345 ...
}

module.exports.DealType = DealType;

/** @enum
 *
 *  Enum describing card color:
 *  - 4 normal colors
 *  - 1 joker color
 *
 */
exports.Card_Color = {
    c: 0, // Clubs
    s: 1, // Spades
    d: 2, // Diamonds
    h: 3, // Hearts
    j: 4  // Rank
}

/*
 *
 *   @function
 *   Detect dealing cards
 *
 * */
function typeDealing(cards) {
    if (cards.length <= 2) {
        return DealType.Pair;
    }
    else {
        var type = DealType.Sequ;
        var rank = cards[0].mRank;
        for (var i = 1; i < cards.length; i++) {
            if (cards[i].mRank == rank) {
                type = DealType.Pair;
                break;
            }
        }
        return type;
    }
}

exports.typeDealing = typeDealing;

// Testing
function Card(rank, color) {
    this.mRank = rank;
    this.mColor = color;
}

//var cards = [new Card(4, 0), new Card(16, 4), new Card(6, 0)];
//
//var type = typeDealing(cards);
//console.log(type);

/*
 *
 *   @function
 *   compare two solutions
 *   -3: Rank
 *   -2: less than and locking hand Ex: 5b 5c < 6b 6c
 *   -1: less than Ex:   5c 5h < 6h 6b
 *   0: Not comparable Ex: 6b 6c ncm 5h 5b 5c; 6b 7b 8b ncm 5h 5b 5c ...
 *   1: large than
 *   2: large than and locking hand
 *   3: Rank
 *
 * */
var cardsCompare = function (cardsX, cardsY) {
    var type = typeDealing(cardsX), len = cardsX.length;
    if (type == typeDealing(cardsY) && len == cardsY.length) {
        if (type == DealType.Pair) {
            if (cardsX.length == 1) {
                if (cardsX[0].mRank == 15) {
                    if(cardsY[0].mRank == 15){
                        if(cardsX[0].mColor < cardsY[0].mColor){
                            return -1
                        }
                        else{
                            return 0;
                        }
                    }
                    else{
                        return 0;
                    }
                }
                else {
                    if (cardsY[0].mRank == 15) {
                        return -2;
                    }
                    if (cardsY[0].mRank != Card_Joker && cardsX[0].mRank != Card_Joker) {
                        if (cardsX[0].mRank < cardsY[0].mRank) {
                            if (cardsX[0].mColor == cardsY[0].mColor) {
                                return -1;
                            }
                        }
                    }
                }

            }
            else {
                if (cardsX[0].mRank < cardsY[0].mRank) {
                    var nsame = 0, joker = false;
                    for (var i = 0; i < len; i++) {
                        var ksame = 1;
                        for (var j = 0; j < len; j++) {
                            if (cardsX[i].mColor == cardsY[j].mColor) {
                                ksame = 0;
                            }
                            else {
                                if (cardsY[j].mRank == Card_Joker || cardsX[i].mRank == Card_Joker) {
                                    joker = true;
                                }
                            }
                        }
                        nsame += ksame;
                    }
                    if (nsame == 0) {
                        return -1;
                    }
                    else {
                        return 0;
                    }
                }
            }

        }

        else {
            // Sequence
            if (cardsX[0].mRank < cardsY[0].mRank) {
                if (cardsX[0].mColor == cardsY[0].mColor) {
                    return -1;
                }
            }
            else {
                return 0;
            }
        }
    }
    else {
        if (cardsX[0].mRank == 15 && cardsX.length == 1) {
            if (this.isTuQuy(cardsY) == true) {
                return -3;
            }
        }
        else {
            return 0;
        }
    }
    return 0;
}
module.exports.cardsCompare = cardsCompare;

/*
 *
 *       Check revolution function
 *
 * */
module.exports.isTuQuy = function (cards) {
    return typeDealing(cards) == DealType.Pair && cards.length >= 4;
}

/*
 *
 *       Check Locking Hand function
 *
 * */


/*
 *       Check eight cut function
 */
module.exports.isEightFlush = function (cards) {
    var ret = false;
    if (cards.length < 3) {
        for (var i = 0; i < cards.length; i++) {
            if (cards[i].mRank == 8) {
                ret = true;
                break;
            }
        }
    }
    if (cards.length > 2) {
        for (var i = 0; i < cards.length; i++) {
            if (cards[i].mRank == 8 && cards[0].mRank == cards[1].mRank) {
                ret = true;
                break;
            }
        }
    }

    return ret;
}

/*
 *       Check cards contain Rank
 */
module.exports.containJoker = function (cards) {
    var ret = null;
    for (var i = 0; i < cards.length; i++) {
        if (cards[i].mRank == Card_Joker) {
            ret = i;
            break;
        }
    }
    return ret;
}

/*
 *       Calculate sum of array
 */
module.exports.sumArray = function (arr) {
    var ret = 0;
    for (var i = 0; i < arr.length; i++) {
        ret += arr[i];
    }
    return ret;
}

/*
 *       Calculate sum of array
 */
module.exports.minArrayPositive = function (arr) {
    var min = Number.POSITIVE_INFINITY;
    for (var i = 0; i < arr.length; i++) {
        if (arr[i] < min && arr[i] > 0) {
            min = arr[i];
        }
    }
    return min;
}

/*
 *       Calculate maximal elemt of array
 */
module.exports.maxArray = function (arr) {
    var max = Number.NEGATIVE_INFINITY;
    for (var i = 0; i < arr.length; i++) {
        if (arr[i] > max) {
            max = arr[i];
        }
    }
    return max;
}

/*
 *
 *
 *       Calculate the combination
 * Check all pattern failed
 *   choose k elements in n element
 * */
module.exports.combination = function (n, k) {
    var norm = 1, denorm = 1;
    for (var i = k; i >= 1; i--) {
        denorm *= i;
        norm *= n - i + 1;
    }

    return norm / denorm;
}

/*
 *
 *       @function
 *       check the solution is in fail pattern or no
 *
 * */
var checkFailSolution = function (cards, isRevolution) {
    var bRet = false;
    var extremism = isRevolution ? 3 : (Card_Joker - 1);
    for (var i = 0; i < cards.length; i++) {
        if (cards[i].mRank == 8 || cards[i].mRank == extremism || cards[i].mRank == Card_Joker) {
            bRet = true;
            break;
        }
    }
    return bRet;
}
module.exports.checkFailSolution = checkFailSolution;

/*
 *
 *       @function
 *       remove all solutions related solution
 *
 * */
var removeRelatedSolution = function (solution, solutions) {
    var newSolutions = [];
    for (var i = 0; i < solutions.length; i++) {
        var find = false;
        for (var k = 0; k < solutions[i].length && !find; k++) {
            for (var j = 0; j < solution.length; j++) {
                if (solution[j].index == solutions[i][k].index) {
                    find = true;
                    break;
                }
            }
        }
        if (!find) {
            newSolutions.push(solutions[i]);
        }
    }
    return newSolutions;
}
module.exports.removeRelatedSolution = removeRelatedSolution;

/*
 *   @function
 *   check a solution is failed by pattern or no
 *   TODO: solution is failed:
 *   + It cover all cards and contain ([2, 3 if revolution], 8, JK)
 *   + The rest cards contains unique ([2, 3 if revolution], 8, JK)
 * */
module.exports.checkPatternFail = function (solution, mCards) {
    var mArrMediate = [];
    var mArrindexofSolution = [];
    var mProphesy = [];
    for (var i = 0; i < mCards.length; i++) {
        if (mCards[i].deal == false) {
            mArrMediate.push(mCards[i].index)
        }
    }
    for (var j = 0; j < solution.length; j++) {
        mArrindexofSolution[j] = solution[j].index;
    }
    for (var k = 0; k < mArrMediate.length; k++) {
        if (mArrindexofSolution.indexOf(mArrMediate[k]) == (-1)) {
            mProphesy.push(mArrMediate[k]);
        }
    }
    if (mProphesy.length == 0) {
        for (var i = 0; i < solution.length; i++) {
            if (solution[i].mRank == 15) {
                return false;
            }
        }
        return true;
    }
    else {
        for (var h = 0; h < mProphesy.length; h++) {
            if (mCards[mProphesy[h]].mRank != 15) {
                return true;
            }
        }
        return false;
    }
}

module.exports.checkJoker = function (solution) {
    for (var i = 0; i < solution.length; i++) {
        if (solution[i].mRank == Card_Joker) {
            return false
        }
    }
    return true;
}
